#include "mainwindow.h"
#include "ui_mainwindow.h"
// #include "camerathread.h"
extern "C" {
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}

#include <QBluetoothLocalDevice>
#include <QBluetoothSocket>
#include <QInputDialog>


#define TCP_STATE_CLINET_CONNECTED     "background-color: #4CAF50;"
#define TCP_STATE_SERVER_CLOSED  "background-color: #F44336;"
#define TCP_STATE_SERVER_OPEN  "background-color: #FFC107;"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    listView_directory_model = new QStringListModel(this);
    ui->listView_directory->setModel( listView_directory_model);


    this->setStyleSheet(
        "QMainWindow {"
        "   background-image: url(G:/Project/QT/testFFmpeg/icon.jpg);" // 使用资源文件路径
        "   background-position: center;"                   // 图片居中
        "   background-repeat: no-repeat;"                  // 不重复
        "   background-attachment: fixed;"                  // 固定背景
        "   background-size: cover;"                        // 覆盖整个窗口
        "}"
        );


    this->setWindowIcon( QIcon("G:\\Project\\QT\\testFFmpeg\\icon.jpg")  );

    const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
    if (cameras.isEmpty()) {
        ui->comboBox_cam->addItem("No cameras found");
        ui->comboBox_cam->setEnabled(false);
        return;
    }
    else{
        for (const QCameraDevice &camera : cameras) {
                ui->comboBox_cam->addItem(camera.description());
        }
    }

    QString localIP = getlocalIP();
    ui->comboBox_ipaddr->addItem( localIP );
    tcp_server = new QTcpServer(this);
    tcp_socket = nullptr;
    connect( tcp_server,SIGNAL( newConnection()) , this , SLOT(do_newConnection()) );

    ui->spinBox_ipaddr->setRange(0,65535);
    ui->spinBox_ipaddr->setValue(8080);

    ui->label_tcpState->setText("TCP server closed");
    ui->label_tcpState->setStyleSheet( TCP_STATE_SERVER_CLOSED);
    ui->pushButton_tcpEnd->setEnabled(false);

    ui->label_captureState->setText( "当前状态：Init" );
    ui->pushButton_faceRegister->setEnabled(false);

    timer_doorState = new QTimer(this);
    timer_doorState->setInterval(1000);
    connect(timer_doorState, &QTimer::timeout, this, &MainWindow::do_timer_doorState_Timeout);
    timer_doorState->stop();


    this->doorState = new ObservableBool() ;

    connect(doorState, &ObservableBool::valueChanged,
            this, &MainWindow::do_updateDoorStatusUi  );

    ui->labe_relayState->setStyleSheet( TCP_STATE_SERVER_CLOSED );
    ui->labe_relayState->setText("Close the door");
}

void MainWindow::do_updateDoorStatusUi(void){

    if(doorState->getValue() == true  ){

        ui->labe_relayState->setStyleSheet( TCP_STATE_CLINET_CONNECTED );
        ui->labe_relayState->setText("Open the door");

    }
    else{
        ui->labe_relayState->setStyleSheet( TCP_STATE_SERVER_CLOSED );
        ui->labe_relayState->setText("Close the door");
    }
}


// int second = 0;
void MainWindow::do_timer_doorState_Timeout( ) {
    if( tcp_socket != nullptr ){
        tcp_socket->write( "AT+CHECK_RELAY");
        QString check_relay =  waitForStringAck(1000,"AT-CHECK");
        qDebug()<<"check_relay is "+ check_relay;
        ui->textBrowser_tcpComm->append( "[in]:ACK Frame: "+check_relay);
        if( check_relay.size()>0 ){
            QChar lastchar = check_relay.at(check_relay.length() -2  );
            if(lastchar == '0')
                this->doorState->setValue(false);
            else if(lastchar == '1' )
                this->doorState->setValue(true);
            qDebug() << "lastchar is " << lastchar  ;
        }
    }
}

void MainWindow::addDevice(const QBluetoothDeviceInfo &device) {
    qDebug() << "Device:" << device.name() << "Address:" << device.address().toString();
}

QString MainWindow::getlocalIP(){
    QString hostName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QList<QHostAddress> ip_addrs = hostInfo.addresses();
    QString localIP = "";
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    const QNetworkInterface * wifi_interface;
    for (const QNetworkInterface &interface : interfaces) {
        // 精确匹配无线局域网适配器
        QString humanName = interface.humanReadableName();
        if (humanName.contains("WLAN", Qt::CaseInsensitive) ||
            humanName.contains("Wireless", Qt::CaseInsensitive) ||
            humanName.contains("Wi-Fi", Qt::CaseInsensitive) ||
            humanName.contains("无线", Qt::CaseInsensitive)) {
            wifi_interface = &interface ;
            break;
        }
    }
    QList<QNetworkAddressEntry> entries = wifi_interface->addressEntries();
    for (const QNetworkAddressEntry &entry : entries) {
        QHostAddress ip = entry.ip();
        if( ip.protocol() == QAbstractSocket::IPv4Protocol ){
            localIP = ip.toString();
            break;
        }
    }
    qDebug() << "localIP :" << localIP;
    return localIP;
};

MainWindow::~MainWindow()
{
    if( tcp_server->isListening() ){
        tcp_server->close();
    }
    delete ui;
}


void MainWindow::do_newConnection(){
    tcp_socket = tcp_server->nextPendingConnection();
    connect( tcp_socket , SIGNAL( connected() ),this, SLOT(do_socketConnected() ) );
    connect( tcp_socket , SIGNAL( readyRead() ),this, SLOT(do_socketReadyRead() ) );
    connect( tcp_socket,  SIGNAL(disconnected()), this, SLOT(do_socketDisconnected()));
    do_socketConnected();
};




void MainWindow::do_socketConnected(){
    qDebug()<< "socket connetcion";
    ui->label_tcpState->setText("TCP client connected");
    ui->label_tcpState->setStyleSheet( TCP_STATE_CLINET_CONNECTED );
    ui->textBrowser_tcpComm->append("TCP client is connected"  );
    timer_doorState->start();
};



void MainWindow::do_socketDisconnected(){

    qDebug()<< "socket disconnetcion";

    ui->label_tcpState->setText("TCP server closed");
    ui->label_tcpState->setStyleSheet( TCP_STATE_SERVER_CLOSED);

    ui->textBrowser_tcpComm->append("TCP client is disconnected"  );
};


void MainWindow::do_socketReadyRead(){
    // while( tcp_socket->canReadLine() ){
    //     ui->textBrowser_tcpComm->append( "[in]:  "+tcp_socket->readLine() );
    // }
    // QByteArray data = tcp_socket->readAll();
    // QString message = QString::fromUtf8(data).trimmed();
    // ui->textBrowser_tcpComm->append( "[in]:  "+message );

}


void MainWindow::on_pushButton_tcpStart_clicked()
{
    QString IP = ui->comboBox_ipaddr->currentText();
    quint16 port = ui->spinBox_ipaddr->value();
    QHostAddress addr(IP);


    tcp_server->listen( addr,port );

    ui->label_tcpState->setText("TCP server start");
    ui->label_tcpState->setStyleSheet( TCP_STATE_SERVER_OPEN );

    ui->pushButton_tcpStart->setEnabled(false);
    ui->pushButton_tcpEnd->setEnabled(true);

}


void MainWindow::on_pushButton_tcpEnd_clicked()
{
    if( tcp_server->isListening() ){
        tcp_server->close();
    }
    ui->label_tcpState->setText("TCP server end");
    ui->label_tcpState->setStyleSheet( TCP_STATE_SERVER_CLOSED);
    ui->pushButton_tcpStart->setEnabled(true);
    ui->pushButton_tcpEnd->setEnabled(false);
}


void MainWindow::on_pushButton_camSuspend_clicked()
{
    if( ui->widget_paint->isSuspend == false)
       ui->widget_paint->isSuspend = true;
    else
        ui->widget_paint->isSuspend = false;
}


void MainWindow::on_pushButton_tcpSend_clicked()
{
    QString send_str = ui->lineEdit_tcpSend->text();
    if( !send_str.isEmpty() ){
        ui->textBrowser_tcpComm->append("[out]:  "+send_str );
        ui->lineEdit_tcpSend->clear();
        QByteArray str = send_str.toUtf8();
        str.append('\n');
        if( tcp_socket != nullptr ) tcp_socket->write( str);
        else {
            QMessageBox::information(this,"TCP Error","TCP Server未开启");
        }
    }
}


QString m_filename;

void MainWindow::on_pushButton_savePicture_clicked()
{
    if(  ui->widget_paint->isSuspend ){
        QString filename = QFileDialog::getSaveFileName(this,"Save Pic",m_filename,filter) ;
        if( filename.isEmpty() ) return;
        ui->widget_paint->suspendFrame.save(filename);
    }
    else{
        QMessageBox::critical(this,"Pic save as","请先暂停视频流");
    }

}


void MainWindow::on_pushButton_openDoor_clicked()
{
    this->timer_doorState->stop();
    if( tcp_socket != nullptr ) {

        if( isDoorOpen == false ){
            tcp_socket->write("AT+OPEN_RELAY" );
            // ui->labe_relayState->setStyleSheet( TCP_STATE_SERVER_OPEN );
            // ui->labe_relayState->setText("Open the door");
            this->doorState->setValue( true );

            ui->textBrowser_tcpComm->append("[out]: AT+OPEN_RELAY" );
            // isDoorOpen = true;
        } else{
            tcp_socket->write( "AT+CLOSE_RELAY");
            ui->textBrowser_tcpComm->append("[out]: AT+CLOSE_RELAY" );
            this->doorState->setValue( false );
        }
    }
    else {
        QMessageBox::information(this,"TCP Error","TCP Server未开启");
    }
    this->timer_doorState->start();
}


void MainWindow::on_pushButton_camSelect_clicked()
{
    avdevice_register_all();
    QString cam =  "video=" + ui->comboBox_cam->currentText();
    qDebug()<<cam;
    const char *deviceName =  cam.toLocal8Bit().constData();
    AVFormatContext *fmt_ctx = nullptr;

    if (avformat_open_input(&fmt_ctx, deviceName, av_find_input_format("dshow"), nullptr) < 0) {
        qDebug() << "无法打开摄像头";
        return;
    }
    // 查找流信息
    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
        qDebug() << "无法获取流信息";
        return;
    } else{
        ui->widget_paint->fmt_ctx = fmt_ctx;
        ui->widget_paint->startPaint();
    }
}


void MainWindow::on_pushButton_camStop_clicked()
{
    ui->widget_paint->stopPaint();

    ui->comboBox_cam->clear();
    const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
    if (cameras.isEmpty()) {
        ui->comboBox_cam->addItem("No cameras found");
        ui->comboBox_cam->setEnabled(false);
        return;
    }
    else{
        for (const QCameraDevice &camera : cameras) {
            ui->comboBox_cam->addItem(camera.description());
        }
    }

}


void MainWindow::on_pushButton_showImage_clicked()
{
    QString cur_path = QDir::currentPath();
    QString filename = QFileDialog::getOpenFileName( this,"选择图片文件",cur_path,filter );
    if( filename.isEmpty() ) return;
    ImageWindow* image_window = new ImageWindow( );
    image_window->setComponents(filename, this->tcp_socket  );
    image_window->setAttribute( Qt::WA_DeleteOnClose  );
    image_window->show();
}


void MainWindow::on_pushButton_captureState_clicked()
{
    this->timer_doorState->stop();
    if( tcp_socket != nullptr ) {

        this->tcp_socket->readAll();
        if(  systemState == INIT || systemState == RUNNING ){
            tcp_socket->write("AT+CAP_START" );
            ui->textBrowser_tcpComm->append("[out]: AT+CAP_START" );
            // if( waitForAck("AT-CAP_START",1000)){
                ui->label_captureState->setText( "当前状态：Capture" );
                systemState = CAPTURE;
                ui->textBrowser_tcpComm->append("[in]: AT-CAP_START" );
                ui->pushButton_faceRegister->setEnabled(true);
                qDebug()<<"CAP_START Success";
            // }
            // else{
            //     qDebug()<<"CAP_START Failed";
            // }
            // ui->labe_relayState->setStyleSheet( TCP_STATE_SERVER_OPEN );
        } else{
            tcp_socket->write( "AT+CAP_END");
            ui->textBrowser_tcpComm->append("[out]: AT+CAP_END" );
            // if( waitForAck("AT-CAP_END",1000)){
                ui->label_captureState->setText( "当前状态：Running" );
                systemState = RUNNING;
                ui->textBrowser_tcpComm->append("[in]: AT-CAP_END" );
                ui->pushButton_faceRegister->setEnabled(false);

                qDebug()<<"CAP_END Success";
            // }
            // else{
            //     qDebug()<<"CAP_END Failed";
            // }
        }
    }
    else {
        QMessageBox::information(this,"TCP Error","TCP Server未开启");
    }
    this->timer_doorState->start();
}


QString MainWindow::waitForStringAck(int timeoutMs,QString ACK)
{
    if (this->tcp_socket == nullptr) {
        return QString(); // 返回空字符串
    }
    // QElapsedTimer timer;
    // timer.start();
    // QString str = "AT-CHECK";
    int size = ACK.size()+1 ;
    while ( this->tcp_socket->bytesAvailable() < size) { // 最小帧大小
        if (!this->tcp_socket->waitForReadyRead(timeoutMs)) {
            return QString(); // 超时
        }
    }
    QByteArray frame = this->tcp_socket->readLine();
    // qDebug()<< "farme is "+ frame;
    QString recv_str = QString::fromLocal8Bit(frame);
    return recv_str;
}



bool MainWindow::waitForAck(QString ACK,int timeoutMs  ) {

    if( this->tcp_socket != nullptr ){
        this->tcp_socket->readAll();
        int ACK_size = ACK.size();
        while ( this->tcp_socket->bytesAvailable() < ACK_size) { // 最小帧大小
            if (!this->tcp_socket->waitForReadyRead(timeoutMs)) {
                return false; // 超时
            }
        }
        // 验证ACK帧
        QByteArray frame = this->tcp_socket->read(ACK_size); // 读取最小帧
        ui->textBrowser_tcpComm->append( "[in]:ACK "+frame);
        if (frame.size() < ACK_size) return false;
        QString recv_str = QString::fromLocal8Bit(frame);  // 本地编码
        return recv_str == ACK;
    }
    else{
        return false;
    }
}

void MainWindow::on_pushButton_faceRegister_clicked()
{
    this->timer_doorState->stop();
    if( this->tcp_socket != nullptr ){
        this->tcp_socket->readAll();
        bool ok;
        QString username = QInputDialog::getText(this,tr("人脸注册"), tr("请输入ID或者姓名:"),
            QLineEdit::Normal,tr("name"),  &ok
        );
        // QString userID = QInputDialog::getText(this,tr("人脸注册"), tr("请输入ID或者姓名:"),
        //                                          QLineEdit::Normal,tr("id"),  &ok
        //                                          );
        if (!ok || username.isEmpty()) {
            QMessageBox::information(this,"TCP Error","用户输入取消");
            return; // 用户取消或未输入
        }else{
            qDebug()<< username;
            this->tcp_socket->write( ("AT+CAP_REGNAME=" + username).toUtf8()  );
            // if( waitForAck("AT-FACE_REG",1000)){
                QMessageBox::information(this,"人脸信息录入","人脸信息录入完成");
            //     qDebug()<<"CAP_END Success";
            // }
        }
    }
    else {
        QMessageBox::information(this,"TCP Error","TCP Server未开启");
    }

    this->timer_doorState->start();
}


void MainWindow::on_pushButton_checkDirectory_clicked()
{
    this->timer_doorState->stop();


    quint8 dir_num =0;
    if( this->tcp_socket != nullptr ){
        this->tcp_socket->readAll();
        this->tcp_socket->write( "AT+CHECK_DIR");
        // QString check_dir_num =  waitForStringAck(500,);

        QString ACK("AT-DIR_NUM");
        int size = ACK.size()+4;
        qDebug()<<size;
        while ( this->tcp_socket->bytesAvailable() < size) { // 最小帧大小
            if (!this->tcp_socket->waitForReadyRead(1000)) {
                break;
            }
        }
        QByteArray frame = this->tcp_socket->readLine();

        // QByteArray frame = this->tcp_socket->read(size);
        qDebug() << "frame is " <<frame;
        QString check_dir_num = frame.data();
        if( check_dir_num.size()>0 ){
            QChar lastchar1 = check_dir_num.at(check_dir_num.length() -2  );
            QChar lastchar2 = check_dir_num.at(check_dir_num.length() -3  );
            QChar lastchar3 = check_dir_num.at(check_dir_num.length() -4  );
            dir_num =  (lastchar3.toLatin1() - '0' )*100 + (lastchar2.toLatin1() - '0' )*10  +(lastchar1.toLatin1() - '0' ) ;
            // qDebug() << "dir_num is " <<dir_num;
        }


        if( dir_num >0 ){
            int single_filename_length = 13;
            int size = single_filename_length*dir_num ;
            while ( this->tcp_socket->bytesAvailable() < size) { // 最小帧大小
                if (!this->tcp_socket->waitForReadyRead(1500)) {
                    break;
                }
            }
            QString frame = this->tcp_socket->readLine();

            QStringList splitList = frame.split(".dat", Qt::SkipEmptyParts);
            qDebug()<<frame;

            if( splitList.size()>0 &&frame.contains(".dat")  ){
                listView_directory_model->setStringList(QStringList());  // 清空数据
                listView_directory_model->setStringList( splitList );
                ui->listView_directory->show();
            }else{
              QMessageBox::information(this,"SD Directory","未录入人脸文件");
               listView_directory_model->setStringList(QStringList());
                 ui->listView_directory->show();
            }

        }else{
            QMessageBox::information(this,"SD Directory","未录入人脸文件");
            listView_directory_model->setStringList(QStringList());
            ui->listView_directory->show();
        }
    }
    else {
        QMessageBox::information(this,"TCP Error","TCP Server未开启");
    }

    this->timer_doorState->start();
}


void MainWindow::on_pushButton_deleteFace_clicked()
{
    this->timer_doorState->stop();
     if( this->tcp_socket != nullptr ){
        this->tcp_socket->readAll();
        QModelIndex currentIndex = ui->listView_directory->currentIndex();
        if (currentIndex.isValid()) {
            QString itemText = listView_directory_model ->data(currentIndex, Qt::DisplayRole).toString();
            quint8 rowAsUint8 = static_cast<quint8>(currentIndex.row());

            QMessageBox::StandardButton reply;
            reply = QMessageBox::question(this, "删除录入人脸", "确认删除"+itemText  ,
                                          QMessageBox::Yes | QMessageBox::No);
            if (reply == QMessageBox::Yes) {
                // 执行删除操作
                QString str = QString( "AT+FACE_DEL%1").arg(rowAsUint8, 2, 16, QChar('0') );
                qDebug()<< str.toUtf8();
                this->tcp_socket->write( str.toUtf8() );
            }


        } else {
            QMessageBox::warning(this, "提示", "未选中任何项");
        }


     }else{
        QMessageBox::information(this,"TCP Error","TCP Server未开启");
     }
    this->timer_doorState->start();
}


